package com.aruio.service.impl;

import com.alibaba.cloud.commons.lang.StringUtils;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.nacos.api.remote.response.ResponseCode;
import com.arui.exception.ServiceException;
import com.aruio.conveter.PandaConverter;
import com.aruio.domain.PandaExportModel;
import com.aruio.domain.PandaImportErrorModel;
import com.aruio.domain.PandaImportModel;
import com.aruio.dto.PandaExcelQueryDTO;
import com.aruio.dto.PandaDTO;
import com.aruio.entity.Panda;
import com.aruio.spring.event.PandaBirthdayEvent;
import com.aruio.spring.event.PandaNotBirthdaySetEvent;
import com.aruio.excel.CommonListener;
import com.aruio.excel.ExcelUtils;
import com.aruio.mapper.PandaMapper;
import com.aruio.service.ExcelTaskService;
import com.aruio.service.PandaService;
import com.aruio.vo.PandaImportVO;
import com.aruio.vo.PandaVO;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Description panda 服务类
 * @Date 2024/9/4 10:15
 * @Created by 10574
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PandaServiceImpl implements PandaService {
    private final PandaMapper pandaMapper;
    private final ExcelTaskService excelTaskService;
    private final ApplicationEventPublisher applicationEventPublisher;
    private static final String UNIQUECODE_EMPTY_MSG = "唯一编码不能为空;";
    private static final String UNIQUECODE_REPEAT_MSG = "唯一编码不能与已有数据重复;";
    private static final String BIRTHDAY_EMPTY_MSG = "生日不能为空;";

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void importExcelV1(MultipartFile file) {
        final CommonListener<PandaImportModel> commonListener = new CommonListener<>(PandaImportModel.class);
        try {
            EasyExcel.read(file.getInputStream(), PandaImportModel.class, commonListener).sheet().doRead();
        } catch (IOException e) {
            log.error("导入熊猫数据出错:{}: {}", e, e.getMessage());
            throw new ServiceException(ResponseCode.FAIL.getCode(), "导入熊猫数据出错，请稍后重试!");
        }
        // 对读取到的数据进行批量保存
        final List<PandaImportModel> excelData = commonListener.getData();
        log.info("excelData:{}", Arrays.toString(excelData.toArray()));
        batchSaveExcelData(excelData);
    }

    @Override
    public void batchSaveExcelData(List<PandaImportModel> excelData) {
        final List<Panda> pandaList = excelData.stream().map(
                pandaImportModel -> {
                    final Panda panda = new Panda();
                    BeanUtils.copyProperties(pandaImportModel, panda, "sex");
                    panda.setSex(pandaImportModel.getSex().equals("男") ? 1 : 0);
                    panda.setCreateTime(new Date());
                    return panda;
                }
        ).collect(Collectors.toList());
        pandaMapper.saveBatch(pandaList);
    }

    @Override
    public void exportByCondition(PandaExcelQueryDTO pandaExcelQueryDTO, HttpServletResponse response) {
        final List<Panda> exportPandasData = pandaMapper.findExportPandas(pandaExcelQueryDTO);
        final List<PandaExportModel> pandaExportModelList = exportPandasData.stream().map(panda -> {
            final PandaExportModel pandaExportModel = new PandaExportModel();
            BeanUtils.copyProperties(panda, pandaExportModel);
            return pandaExportModel;
        }).collect(Collectors.toList());

        try {
            final String filename = "熊猫基本信息集合-" + System.currentTimeMillis();
//            ExcelUtils.exportExcelToOSS()
            ExcelUtils.exportExcel(PandaExportModel.class, pandaExportModelList, filename, ExcelTypeEnum.XLSX, response);
        } catch (IOException e) {
            log.error("熊猫导出数据失败:{}, {}", e, e.getMessage());
            throw new ServiceException("熊猫基本信息导出失败, 请稍后再试！");
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public PandaImportVO<?> importExcelV2(MultipartFile file) {
        final CommonListener<PandaImportModel> commonListener = new CommonListener<>(PandaImportModel.class);
        try {
            EasyExcel.read(file.getInputStream(), PandaImportModel.class, commonListener);
        } catch (IOException e) {
            log.error("导入熊猫数据出错:{}: {}", e, e.getMessage());
            throw new ServiceException(ResponseCode.FAIL.getCode(), "导入熊猫数据出错，请稍后重试!");
        }
        final List<PandaImportModel> excelData = commonListener.getData();
        log.info("excelData:{}", Arrays.toString(excelData.toArray()));
        // 对读取到的数据校验是否为空
        if (CollectionUtils.isEmpty(excelData)) {
            throw new ServiceException(ResponseCode.FAIL.getCode(), "请检查您上传的excel文件是否为空！");
        }

        //对读取到的数据进行业务上的校验
        final PandaImportVO<?> pandaImportVO = validateExcelData(excelData);
        if (pandaImportVO.getErrorFlag()) {
            return pandaImportVO;
        }

        // 对读取到的数据进行批量保存
        batchSaveExcelData(excelData);
        return pandaImportVO;
    }

    @Override
    public Integer exportPandaExcelV2(HttpServletResponse response) {
//        // 先插入一条报表任务记录
//        final ExcelTask excelTask = new ExcelTask();
//        excelTask.setTaskType(ExcelTaskType.EXPORT.getCode());
//        excelTask.setHandleStatus(TaskHandleStatus.WAIT_HANDLE.getCode());
//        excelTask.setCreateTime(new Date());
//        excelTaskService.save(excelTask);
//        Long taskId = excelTask.getTaskId();
//
//        // 将报表导出任务提交给异步线程池
//        ThreadPoolTaskExecutor asyncPool = TaskThreadPool.getAsyncThreadPool();
//
//        // 必须用try包裹，因为线程池已满时任务被拒绝会抛出异常
//        try {
//            asyncPool.submit(() -> {
//                handleExportTask(taskId);
//            });
//        } catch (RejectedExecutionException e) {
//            // 记录等待恢复的状态
//            log.error("递交异步导出任务被拒，线程池任务已满，任务ID：{}", taskId);
//            ExcelTask editTask = new ExcelTask();
//            editTask.setTaskId(taskId);
//            editTask.setHandleStatus(TaskHandleStatus.WAIT_TO_RESTORE.getCode());
//            editTask.setExceptionType("异步线程池任务已满");
//            editTask.setErrorMsg("等待重新载入线程池被调度！");
//            editTask.setUpdateTime(new Date());
//            excelTaskService.updateById(editTask);
//        }
//        return taskId;
        return 0;
    }

    @Override
    public List<PandaVO> queryPandas(PandaDTO pandaDTO) {
        return pandaMapper.queryPandas(pandaDTO);
    }

    @Override
    public PandaVO queryPanda(PandaDTO pandaDTO) {
        final Panda panda = pandaMapper.queryPanda(pandaDTO);
        // 判断熊猫过了生日，给熊猫发生日优惠卷提醒短信
        final LocalDate birthday = panda.getBirthday();
        if (Objects.isNull(birthday)) {
            //生日未记录事件(发送短信提醒未设置生日)
            applicationEventPublisher.publishEvent(new PandaNotBirthdaySetEvent(panda));
        }
        if (Objects.nonNull(birthday) && !LocalDate.now().isBefore(birthday)) {
            // 到达生日事件（需要多个监听器去新增优惠卷到熊猫用户 发送短信监听器）
            applicationEventPublisher.publishEvent(new PandaBirthdayEvent((panda)));
        }
        return PandaConverter.toVO(panda);
    }

    private PandaImportVO<?> validateExcelData(List<PandaImportModel> pandaImportModelList) {
        final PandaImportVO<Object> pandaImportVO = new PandaImportVO<>();
        boolean errorFlag = false;
        final List<PandaImportErrorModel> pandaImportErrorModelList = new ArrayList<>();
//        Map map = new HashMap();
        // 1. 校验所有数据
        for (PandaImportModel model : pandaImportModelList) {
            //唯一编码不能为空，为空则错误
            final StringBuilder errorMsg = new StringBuilder();
            boolean lineErrorFlag = false;
            if (StringUtils.isBlank(model.getUniqueCode())) {
                errorMsg.append(UNIQUECODE_EMPTY_MSG);
                lineErrorFlag = true;
            }
            //TODO 校验库中是否存在重复的唯一编码
            if (null == model.getBirthday()) {
                errorMsg.append(BIRTHDAY_EMPTY_MSG);
                lineErrorFlag = true;
            }
            if (lineErrorFlag) {
                errorFlag = true;
                final PandaImportErrorModel pandaImportErrorModel = new PandaImportErrorModel();
                BeanUtils.copyProperties(model, pandaImportErrorModel);
                pandaImportErrorModel.setErrorMsg(errorMsg.toString());
                pandaImportErrorModelList.add(pandaImportErrorModel);
            }
        }
        pandaImportVO.setErrorFlag(errorFlag);
        pandaImportVO.setResult(pandaImportErrorModelList);
        if (errorFlag) {
            pandaImportVO.setCheckMsg("文件校验未通过!");
        }
        return pandaImportVO;
//        final List<String> uniqueCodes = pandaImportModelList.stream()
//                .map(PandaImportModel::getUniqueCode)
//                .collect(Collectors.toList());

    }

    private void handleExportTask(Long taskId) {
//        long startTime = System.currentTimeMillis();
//        log.info("处理报表导出任务开始，编号：{}，时间戳：{}", taskId, startTime);
//        // 开始执行时，先将状态推进到进行中
//        excelTaskService.updateStatus(taskId, TaskHandleStatus.IN_PROGRESS.getCode());
//
//        // 需要修改的报表对象
//        ExcelTask editTask = new ExcelTask();
//        editTask.setTaskId(taskId);
//
//        // 查询导出的总行数，如果为0，说明没有数据要导出，直接将任务推进到失败状态
//        int totalRows = pandaMapper.selectTotalRows();
//        if (totalRows == 0) {
//            editTask.setHandleStatus(TaskHandleStatus.FAILED.getCode());
//            editTask.setExceptionType("数据为空");
//            editTask.setErrorMsg("对应导出任务没有数据可导出！");
//            editTask.setUpdateTime(new Date());
//            excelTaskService.updateById(editTask);
//            return;
//        }
//
//        // 总数除以每批数量，并向上取整得到批次数
//        int batchRows = 2000;
//        int batchNum = totalRows / batchRows + (totalRows % batchRows == 0 ? 0 : 1);
//        // 总批次数除以并发比例，并向上取整得到并发轮数
//        int concurrentRound = batchNum / TaskThreadPool.concurrentRate
//                + (batchNum % TaskThreadPool.concurrentRate == 0 ? 0 : 1);;
//
//        log.info("本次报表导出任务-目标数据量：{}条，每批数量：{}，总批次数：{}，并发总轮数：{}",
//                totalRows, batchRows, batchNum, concurrentRound);
//
//        // 提前创建excel写入对象（这里可以替换成上传至文件服务器）
//        String fileName = "百万级熊猫数据-" + startTime + ".csv";
//        ExcelWriter excelWriter = EasyExcelFactory.write(fileName, PandaImportVO.class)
//                .excelType(ExcelTypeEnum.CSV)
//                .build();
//        // CSV文件这行其实可以不需要，设置了也不会生效
//        WriteSheet writeSheet = EasyExcelFactory.writerSheet(0, "百万熊猫数据").build();
//
//        // 根据计算出的并发轮数开始并发读取表内数据处理
//        AtomicInteger cursor = new AtomicInteger(0);
//        ThreadPoolTaskExecutor concurrentPool = TaskThreadPool.getConcurrentThreadPool();
//        for (int i = 1; i <= concurrentRound; i++) {
//            CountDownLatch countDownLatch = new CountDownLatch(TaskThreadPool.concurrentRate);
//            final CopyOnWriteArrayList<PandaImportVO> data = new CopyOnWriteArrayList<>();
//            for (int j = 0; j < TaskThreadPool.concurrentRate; j++) {
//                final int startId = cursor.get() * batchRows + 1;
//                concurrentPool.submit(() -> {
//                    List<PandaImportVO> pandas = pandaMapper.selectPandaPage((long) startId, batchRows);
//                    if (null != pandas && pandas.size() != 0) {
//                        data.addAll(pandas);
//                    }
//                    countDownLatch.countDown();
//                });
//                cursor.incrementAndGet();
//            }
//
//            try {
//                countDownLatch.await();
//            } catch (InterruptedException e) {
//                editTask.setHandleStatus(TaskHandleStatus.FAILED.getCode());
//                editTask.setExceptionType("导出等待中断");
//                editTask.setErrorMsg(e.getMessage());
//                editTask.setUpdateTime(new Date());
//                excelTaskService.updateById(editTask);
//                return;
//            }
//            excelWriter.write(data, writeSheet);
//            // 手动清理每一轮的集合数据，用于辅助GC
//            data.clear();
//        }
//
//        log.info("处理报表导出任务结束，编号：{}，导出耗时（ms）：{}",
//                taskId, System.currentTimeMillis() - startTime);
//        // 完成写入后，主动关闭资源
//        excelWriter.finish();
//
//        // 如果执行到最后，说明excel导出成功，将状态推进到导出成功
//        editTask.setHandleStatus(TaskHandleStatus.SUCCEED.getCode());
//        editTask.setExcelUrl(fileName);
//        editTask.setUpdateTime(new Date());
//        excelTaskService.updateById(editTask);
    }
}
